﻿/* ######################################## *\
 * ### Copyright (C) 2009 AJ Ravindiran ### *
\* ######################################## */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using AJRavindiran.Jolt.RuneScape.Models.Characters;
using AJRavindiran.Jolt.RuneScape.Network.Packets.Builders;
using AJRavindiran.Jolt.RuneScape.Network.Packets.Handlers;

namespace AJRavindiran.Jolt.RuneScape.Network.Packets
{
    /// <summary>
    /// Represents a manager for all packet related content.
    /// </summary>
    public class PacketManager
    {
        #region Fields
        private CharacterFramesOpcode frames = new CharacterFramesOpcode();
        private PacketSizes packetSizes = new PacketSizes();
        private Dictionary<int, IPacketHandler> handlers = new Dictionary<int, IPacketHandler>();

        private PacketBuilder packetBuilder = new PacketBuilder();
        #endregion Fields

        #region Constructors
        /// <summary>
        /// Constructs a new packet manager class.
        /// </summary>
        public PacketManager()
        {
            Jolt.GetLog().WriteInfo("Constucting packet manager...");
            this.packetSizes.SetPacketSizes();
        }
        #endregion Constructors

        #region Methods
        /// <summary>
        /// Handles a packet requested from a session.
        /// </summary>
        /// <param name="character">Character requesting packet</param>
        /// <param name="packetId">Packet id to be handled</param>
        /// <param name="packetSize">Packet byte size being sent</param>
        public void HandlePacket(Character character, int packetId, int packetSize)
        {
            try
            {
                IPacketHandler handler = handlers[packetId];
                if (handler == null)
                    Jolt.GetLog().WriteWarn("Unhandled packet: " + packetId);
                else
                    handler.HandlePacket(character, packetId, packetSize);
            }
            catch (Exception) 
            { 
                // Invaid packets would show here, but since we 
                // are already handling, no point putting it here.
            }
        }

        public void ParseImconingPackets()
        {
            int avail = 0;
            int packetId = 0;
            int packetSize = 0;

            foreach (Character c in RuneScape.GetCharacterManager().GetCharacters().Values)
            {
                if (!c.GetStatus().Online || c.GetStatus().Disconnected[0])
                    continue;

                try
                {
                    for (int i = 0; i < 10; i++)
                    {
                        avail = c.GetSocket().Availible;

                        if (avail < 1)
                            break;

                        packetId = c.GetSocket().Read() & 0xff;
                        avail--;

                        if (packetId < 0 || packetId > 255)
                            break;

                        packetSize = (int)packetSizes.Sizes[packetId];

                        if (packetSize == -1)
                            if (avail > 0)
                            {
                                packetSize = c.GetSocket().Read() & 0xff;
                                avail--;
                            }
                            else
                            {
                                break;
                            }
                        else if (packetSize == -3)
                            packetSize = avail;
                        if (packetSize > avail)
                            break;
                        if (packetSize >= 500)
                            break;

                        c.GetStreamReader().ReadOffset = 0;
                        c.GetSocket().Read(packetSize);
                        HandlePacket(c, packetId, packetSize);
                    }
                }
                catch (PacketException pex)
                {
                    Jolt.GetLog().WriteException(pex);
                    c.GetStatus().Disconnected[0] = true;
                }
            }
        }

        /// <summary>
        /// Get accessor for the character frames opcode.
        /// </summary>
        public CharacterFramesOpcode GetFrames()
        {
            return this.frames;
        }

        /// <summary>
        /// Get accessor for the packet builder.
        /// </summary>
        public PacketBuilder GetBuilder()
        {
            return this.packetBuilder;
        }
        #endregion Methods
    }
}
